#include <gtk/gtk.h>
#include <jni.h>
#include "gtkwire_utils.h"
#include "gtkwire_app.h"
#include "gtkwire_databank.h"

/* vm instance */
static JavaVM *jvm = NULL;

/* Class Objects */
static jclass integer_cls = 0;
static jclass double_cls = 0;
static jclass string_cls = 0;
static jclass boolean_cls = 0;

/* Method ids */
static jmethodID integer_constr_mid = 0;
static jmethodID double_constr_mid = 0;
static jmethodID string_constr_mid = 0;
static jmethodID boolean_constr_mid = 0;

void 
init_utils (JNIEnv *env)
{
	/* Initialize the jvm global variable */
	(*env)->GetJavaVM (env, &jvm);

	/* Get class obejcts and make global refs */
	jclass integer_cls_l = (*env)->FindClass (env, "java/lang/Integer");
	integer_cls = (*env)->NewGlobalRef (env, integer_cls_l);
	jclass double_cls_l = (*env)->FindClass (env, "java/lang/Double");
	double_cls = (*env)->NewGlobalRef (env, double_cls_l );
	jclass string_cls_l = (*env)->FindClass (env, "java/lang/String");
	string_cls = (*env)->NewGlobalRef (env, string_cls_l );
	jclass boolean_cls_l = (*env)->FindClass (env, "java/lang/Boolean");
	boolean_cls = (*env)->NewGlobalRef (env, boolean_cls_l);

	/* Get java method ids for message constructors */
	integer_constr_mid = (*env)->GetMethodID (env, integer_cls, "<init>", "(I)V");
	double_constr_mid = (*env)->GetMethodID (env, double_cls, "<init>", "(D)V");
	string_constr_mid = (*env)->GetMethodID (env, string_cls, "<init>", "(Ljava/lang/String;)V");
	boolean_constr_mid = (*env)->GetMethodID (env, boolean_cls, "<init>", "(Z)V");
}

GType
get_gtype (int g_type_java)
{
	switch (g_type_java)
	{
		case G_TYPE_INVALID_JAVA:
			return G_TYPE_INVALID;

		case G_TYPE_NONE_JAVA:
			return G_TYPE_NONE;

		case G_TYPE_INTERFACE_JAVA:
			return G_TYPE_INTERFACE;

		case G_TYPE_CHAR_JAVA:
			return G_TYPE_CHAR;

		case G_TYPE_UCHAR_JAVA:
			return G_TYPE_UCHAR;

		case G_TYPE_BOOLEAN_JAVA:
			return G_TYPE_BOOLEAN;

		case G_TYPE_INT_JAVA:
			return G_TYPE_INT;

		case G_TYPE_UINT_JAVA:
			return G_TYPE_UINT;

		case G_TYPE_LONG_JAVA:
			return G_TYPE_LONG;

		case G_TYPE_ULONG_JAVA:
			return G_TYPE_ULONG;

		case G_TYPE_INT64_JAVA:
			return G_TYPE_INT64;

		case G_TYPE_UINT64_JAVA:
			return G_TYPE_UINT64;

		case G_TYPE_ENUM_JAVA:
			return G_TYPE_ENUM;

		case G_TYPE_FLAGS_JAVA:
			return G_TYPE_FLAGS;

		case G_TYPE_FLOAT_JAVA:
			return G_TYPE_FLOAT;

		case G_TYPE_DOUBLE_JAVA:
			return G_TYPE_DOUBLE;

		case G_TYPE_STRING_JAVA:
			return G_TYPE_STRING;

		case G_TYPE_POINTER_JAVA:
			return G_TYPE_POINTER;

		case G_TYPE_BOXED_JAVA:
			return G_TYPE_BOXED;

		case G_TYPE_PARAM_JAVA:
			return G_TYPE_PARAM;

		case G_TYPE_OBJECT_JAVA:
			return G_TYPE_OBJECT;

		case G_TYPE_GTYPE_JAVA:
			return G_TYPE_GTYPE;

		case GDK_TYPE_PIXBUF_JAVA:
			return GDK_TYPE_PIXBUF;

		default:
			return G_TYPE_INVALID;
	}
} 

jobject
get_jobject_for_GValue(JNIEnv *env, GValue *val )
{
	const char *str;
	int i;
	double d;
	gboolean b;
	
	switch(G_VALUE_TYPE(val))
	{
		case M_DOUBLE:
			d = g_value_get_double (val);
			return (*env)->NewObject (env, double_cls, double_constr_mid, d);

		case G_TYPE_INT:
			i = g_value_get_int (val);
			return (*env)->NewObject (env, integer_cls, integer_constr_mid, i);

		case M_BOOLEAN:
			b = g_value_get_boolean (val);
			return (*env)->NewObject (env, boolean_cls, boolean_constr_mid, b);

		case G_TYPE_STRING:
			str = g_value_get_string (val);
			return (*env)->NewStringUTF (env, str);
	}
	
	return NULL;
}

GValue 
get_gvalue (GType gtype, const char *data)
{
	GValue gval = { 0, };
	
	switch( gtype )
	{
		case G_TYPE_INT:
			g_value_init( &gval, G_TYPE_INT );
			int i = atoi( data);
			g_value_set_int (&gval, i );
			break;

		case G_TYPE_DOUBLE:
			g_value_init( &gval, G_TYPE_DOUBLE );
			double d = atof( data);
			g_value_set_double (&gval, d );
			break;

		case G_TYPE_BOOLEAN:
			g_value_init( &gval, G_TYPE_BOOLEAN );
			gboolean b = str_to_boolean (data);
			g_value_set_boolean (&gval, b );
			break;

		case G_TYPE_STRING:
			g_value_init (&gval, G_TYPE_STRING);
			g_value_set_string (&gval, data);
			break;

		case G_TYPE_OBJECT:
/*
			g_value_init (&gval, G_TYPE_OBJECT);
			g_value_set_object (&gval, data);
*/
			break;
			
	}


	return gval;
}

void
set_gobject_property (GObject *obj, GType property_type, const gchar *property, const gchar *value)
{
	GValue gval = { 0, };
	gval = get_gvalue (property_type, value);
	g_object_set_property               (obj,property,&gval);

}

void 
set_boolean_property (GObject *obj, const gchar *property, gboolean b)
{
	GValue gval = { 0 };
	g_value_init( &gval, G_TYPE_BOOLEAN );
	g_value_set_boolean( &gval, b );
	g_object_set_property( obj, property, &gval );
}

void 
set_string_property (GtkWidget *widget, const gchar *property, const gchar *str)
{
	GValue gval = { 0 };
	g_value_init (&gval, G_TYPE_STRING);
	g_value_set_string (&gval, str);
	g_object_set_property (G_OBJECT(widget), property, &gval);
}

GList* 
get_double_value_glist (gdouble *arr, gint arr_len)
{
	GList *glist = NULL;
	int i;
	for (i = 0; i < arr_len; i++)
		glist = g_list_append (glist, (gpointer) &arr[ i ]);
	return glist;
}

const char* 
read_str_from_glist (gpointer data, int index)
{
	GList *glist = data;
	int i;
	for( i = 0; i < index; i++ )
		glist = glist->next;
	return glist->data;
}

gboolean 
str_to_boolean (const char *boolStr)
{
	if (strcmp(boolStr, BOOLEAN_STR_TRUE) == 0)
		return TRUE;
	else 
		return FALSE;
}

gboolean
widget_is (GtkWidget *widget, const char *type_name)
{
	const gchar *widget_type = g_type_name (G_OBJECT_TYPE(widget));

	if (strcmp(widget_type, type_name) == 0) 
		return TRUE;
	else 
		return FALSE;
}

int
get_icon_size (const char *idStr)
{
	if (strcmp(idStr, "GTK_ICON_SIZE_DIALOG") == 0) return GTK_ICON_SIZE_DIALOG;
	if (strcmp(idStr, "GTK_ICON_SIZE_MENU") == 0) return GTK_ICON_SIZE_MENU;
	if (strcmp(idStr, "GTK_ICON_SIZE_SMALL_TOOLBAR") == 0) return GTK_ICON_SIZE_SMALL_TOOLBAR;
	if (strcmp(idStr, "GTK_ICON_SIZE_LARGE_TOOLBAR" ) == 0) return GTK_ICON_SIZE_LARGE_TOOLBAR;
	if (strcmp(idStr, "GTK_ICON_SIZE_BUTTON") == 0) return GTK_ICON_SIZE_BUTTON;
	if (strcmp(idStr, "GTK_ICON_SIZE_DND") == 0) return  GTK_ICON_SIZE_DND;
	return GTK_ICON_SIZE_INVALID;
}

int
get_pango_ellipsize_mode (const char *idStr)
{
	if (strcmp(idStr, "PANGO_ELLIPSIZE_NONE") == 0) return PANGO_ELLIPSIZE_NONE;
	if (strcmp(idStr, "PANGO_ELLIPSIZE_START") == 0) return PANGO_ELLIPSIZE_START;
	if (strcmp(idStr, "PANGO_ELLIPSIZE_MIDDLE") == 0) return PANGO_ELLIPSIZE_MIDDLE;
	if (strcmp(idStr, "PANGO_ELLIPSIZE_END") == 0) return PANGO_ELLIPSIZE_END;
	return PANGO_ELLIPSIZE_NONE;
}

int
get_gtk_justification (const char *idStr)
{
	if (strcmp(idStr, "GTK_JUSTIFY_LEFT") == 0) return GTK_JUSTIFY_LEFT;
	if (strcmp(idStr, "GTK_JUSTIFY_RIGHT") == 0) return GTK_JUSTIFY_RIGHT;
	if (strcmp(idStr, "GTK_JUSTIFY_CENTER") == 0) return GTK_JUSTIFY_CENTER;
	if (strcmp(idStr, "GTK_JUSTIFY_FILL") == 0) return GTK_JUSTIFY_FILL;
	return GTK_JUSTIFY_LEFT;
}

int
get_gtk_wrap (const char *idStr)
{
	if (strcmp(idStr, "GTK_WRAP_NONE") == 0) return GTK_WRAP_NONE;
	if (strcmp(idStr, "GTK_WRAP_CHAR") == 0) return GTK_WRAP_CHAR;
	if (strcmp(idStr, "GTK_WRAP_WORD") == 0) return GTK_WRAP_WORD;
	if (strcmp(idStr, "GTK_WRAP_WORD_CHAR") == 0) return GTK_WRAP_WORD_CHAR;
	return GTK_WRAP_NONE;
}

int
get_gtk_pos (const char *idStr)
{
	if (strcmp(idStr, "GTK_POS_LEFT") == 0) return GTK_POS_LEFT;
	if (strcmp(idStr, "GTK_POS_RIGHT") == 0) return GTK_POS_RIGHT;
	if (strcmp(idStr, "GTK_POS_TOP") == 0) return GTK_POS_TOP;
	if (strcmp(idStr, "GTK_POS_BOTTOM") == 0) return GTK_POS_BOTTOM;
	return GTK_WRAP_NONE;
}

int 
get_gtk_resize_mode (const char *idStr)
{
	if (strcmp(idStr, "GTK_RESIZE_PARENT") == 0) return GTK_RESIZE_PARENT;
	if (strcmp(idStr, "GTK_RESIZE_QUEUE") == 0) return GTK_RESIZE_QUEUE;
	if (strcmp(idStr, "GTK_RESIZE_IMMEDIATE") == 0) return GTK_RESIZE_IMMEDIATE;
	return GTK_RESIZE_IMMEDIATE;
}


int
get_gtk_progress_orientation (int orient)
{
	//--- values hardcoded in GtkProgressBar.java
	if (orient == 0) return GTK_PROGRESS_LEFT_TO_RIGHT;
	if (orient == 1) return GTK_PROGRESS_RIGHT_TO_LEFT;
	if (orient == 2) return GTK_PROGRESS_BOTTOM_TO_TOP;
	return GTK_PROGRESS_TOP_TO_BOTTOM;
}

int 
get_gtk_attach_options (const char *idStr )
{
	if (strcmp(idStr, "GTK_EXPAND") == 0) return GTK_EXPAND;
	if (strcmp(idStr, "GTK_SHRINK") == 0) return GTK_SHRINK;
	return GTK_FILL;
}

int 
get_gtk_update_policy (const char *idStr )
{
	if (strcmp(idStr, "GTK_UPDATE_CONTINUOUS") == 0) return GTK_UPDATE_CONTINUOUS;
	if (strcmp(idStr, "GTK_UPDATE_DISCONTINUOUS") == 0) return GTK_UPDATE_DISCONTINUOUS;
	return GTK_UPDATE_DELAYED;
}

int 
get_gtk_widget_orientation (const char *idStr )
{
	if (strcmp(idStr,"GTK_HORIZONTAL") == 0) return GTK_ORIENTATION_HORIZONTAL;
	if (strcmp(idStr,"GTK_VERTICAL") == 0) return GTK_ORIENTATION_VERTICAL;
}

int
get_get_toolbar_style (const char *idStr )
{
	if (strcmp(idStr, "GTK_TOOLBAR_ICONS") == 0) return GTK_TOOLBAR_ICONS;
	if (strcmp(idStr, "GTK_TOOLBAR_TEXT") == 0) return GTK_TOOLBAR_TEXT;
	if (strcmp(idStr, "GTK_TOOLBAR_BOTH") == 0) return GTK_TOOLBAR_BOTH;
	return GTK_TOOLBAR_BOTH;
}

int
get_get_buttonbox_style (const char *idStr )
{
	if (strcmp(idStr, "GTK_BUTTONBOX_DEFAULT_STYLE") == 0) return GTK_BUTTONBOX_DEFAULT_STYLE;
	if (strcmp(idStr, "GTK_BUTTONBOX_SPREAD") == 0) return GTK_BUTTONBOX_SPREAD;
	if (strcmp(idStr, "GTK_BUTTONBOX_EDGE") == 0) return GTK_BUTTONBOX_EDGE;
	if (strcmp(idStr, "GTK_BUTTONBOX_START") == 0) return GTK_BUTTONBOX_START;
	return  GTK_BUTTONBOX_END;
//	if (strcmp(idStr, "GTK_BUTTONBOX_CENTER") == 0) return GTK_BUTTONBOX_CENTER;
}

int 
get_gtk_window_type (const char *idStr)
{
	if (strcmp(idStr, "GTK_WINDOW_POPUP") == 0) return GTK_WINDOW_POPUP;
	return GTK_WINDOW_TOPLEVEL;
}

int 
get_gtk_file_chooser_mode (const char *idStr)
{
	if (strcmp(idStr, "GTK_FILE_CHOOSER_ACTION_OPEN") == 0) return GTK_FILE_CHOOSER_ACTION_OPEN;
	if (strcmp(idStr, "GTK_FILE_CHOOSER_ACTION_SAVE") == 0) return GTK_FILE_CHOOSER_ACTION_SAVE;
	if (strcmp(idStr, "GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER") == 0) return GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
	return GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
}
